In Microsoft Windows programming, keyboard and mouse input always go to particular controls. Keyboard
input always goes to the control with the input focus. Mouse input
always goes to the topmost enabled control under the mouse pointer. Stylus and touch
input is handled similarly to the mouse. But sometimes this is
inconvenient. Sometimes the control underneath needs the user-input more
than the control on top.
To be a bit more flexible, Silverlight implements a system called routed event handling. Most user input events—including the three Manipulation events—do indeed originate using the same paradigm as Windows. The Manipulation
events originate at the topmost enabled element touched by the user.
However, if that element is not interested in the event, the event then
goes to that element’s parent, and so forth up the visual tree ending at
the PhoneApplicationFrame
element. Any element along the way can grab the input and do something
with it, and also inhibit further progress of the event up the tree.
This is why you can override the OnManipulationStarted method in MainPage and also get manipulation events for the TextBlock. By default the TextBlock isn’t interested in those events.
The event argument for the ManipulationStarted event is ManipulationStartedEventArgs, which derives from RoutedEventArgs. It is RoutedEventArgs that defines the OriginalSource property that indicates the element on which the event began.
But this suggests another
approach that combines the two techniques shown in SilverlightTapHello1
and SilverlightTapHello2. Here’s the XAML file of SilverlightTapHello3:
Example 1. Silverlight Project: SilverlightTapHello3 File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Name="txtblk" Text="Hello, Windows Phone 7!" Padding="0 34" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationStarted="OnTextBlockManipulationStarted" /> </Grid>
|
The TextBlock has a Name as in the first program. A handler for the ManipulationStarted event is set on the TextBlock as in the first program. Both the event handler and an override of OnManipulationStarted appear in the code-behind file:
Example 2. Silverlight Project: SilverlightTapHello3 File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage { Random rand = new Random(); Brush originalBrush;
public MainPage() { InitializeComponent(); originalBrush = txtblk.Foreground; }
void OnTextBlockManipulationStarted(object sender, ManipulationStartedEventArgs args) { txtblk.Foreground = new SolidColorBrush( Color.FromArgb(255, (byte)rand.Next(256), (byte)rand.Next(256), (byte)rand.Next(256))); args.Complete(); args.Handled = true; }
protected override void OnManipulationStarted(ManipulationStartedEventArgs args) { txtblk.Foreground = originalBrush;
args.Complete(); base.OnManipulationStarted(args); } }
|
The logic has been split between the two methods, making the whole thing rather more elegant, I think. The OnTextBlockManipulationStarted method only gets events when the TextBlock is touched. The OnManipulationStarted event gets all events for MainPage.
At first there might seem to be a bug here. After OnTextBlockManipulationStarted is called, the event continues to travel up the visual tree and OnManipulationStarted
sets the color back to white. But that’s not what happens: The crucial
statement that makes this work right is this one at the end of the OnTextBlockManipulationStarted handler for the TextBlock:
args.Handled = true;
That statement says that the event has now been handled and it should not travel further up the visual tree. Remove that statement and the TextBlock never changes from its initial color—at least not long enough to see.